import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { simulateSinglePositionStrategy } from "./strategy-single-10-sell-3.js";
import { Op } from 'sequelize';
import utils from '../utils/index.js';
import _ from 'lodash';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const configPath = path.join(__dirname, "config.json");
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));

console.log(config);

const defineKline3MModel = async (db, DataTypes) => {
  return db.define('klines_3M', {
    symbol: {
      type: DataTypes.CHAR(60),
      allowNull: false,
      primaryKey: true,
    },
    open_time: {
      type: DataTypes.BIGINT(13).UNSIGNED,
      allowNull: false,
      defaultValue: 0,
      primaryKey: true,
    },
    open: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    high: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    low: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    close: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    volume: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    close_time: {
      type: DataTypes.BIGINT(13).UNSIGNED,
      allowNull: false,
      defaultValue: 0,
    },
    quote_volume: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    count: {
      type: DataTypes.INTEGER.UNSIGNED,
      allowNull: false,
      defaultValue: 0,
    },
    taker_buy_volume: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    taker_buy_quote_volume: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
  }, {
    timestamps: false,
    freezeTableName: true,
  });
};

const Kline3M = utils.DB.defineModel(defineKline3MModel);

// 计算回撤的函数
const calculateDrawdown = (profits) => {
  let peak = 0;
  let cumulative = 0;
  let maxDrawdown = 0;
  let currentDrawdown = 0;

  for (const profit of profits) {
    cumulative += profit;
    if (cumulative > peak) {
      peak = cumulative;
      currentDrawdown = 0;
    } else {
      currentDrawdown = peak - cumulative;
      if (currentDrawdown > maxDrawdown) {
        maxDrawdown = currentDrawdown;
      }
    }
  }

  return {
    maxDrawdown,
    finalValue: cumulative,
    peakValue: peak
  };
};

// 生成日期范围内的所有日期
const generateDateRange = (startTime, endTime) => {
  const dates = [];
  const startDate = new Date(startTime);
  const endDate = new Date(endTime);

  for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
    dates.push(new Date(d));
  }

  return dates;
};

// 获取指定日期的数据
const getDataForDate = async (model, date) => {
  const startOfDay = new Date(date);
  startOfDay.setHours(0, 0, 0, 0);

  const endOfDay = new Date(date);
  endOfDay.setHours(23, 59, 59, 999);

  const startTimestamp = startOfDay.getTime();
  const endTimestamp = endOfDay.getTime();

  return await model.findAll({
    where: {
      open_time: {
        [Op.between]: [startTimestamp, endTimestamp]
      }
    },
    order: [['open_time', 'ASC']]
  });
};

// 格式化北京时间的函数
const formatBeijingTime = (date) => {
  return new Date(date.getTime() + 8 * 60 * 60 * 1000).toISOString().split('T')[0];
};

// 格式化北京时间的详细时间
const formatBeijingDateTime = (date) => {
  const beijingDate = new Date(date.getTime() + 8 * 60 * 60 * 1000);
  return beijingDate.toISOString().replace('T', ' ').substring(0, 19);
};

// 解析命令行参数，优先使用传参的 startDate 和 endDate
function parseDateArg(argName) {
  const arg = process.argv.find(a => a.startsWith(`--${argName}=`));
  if (arg) {
    const value = arg.split('=')[1];
    // 支持时间戳或日期字符串
    if (!isNaN(Number(value))) {
      return Number(value);
    } else {
      return new Date(value).getTime();
    }
  }
  return null;
}

(async () => {
  const model = await Kline3M;

  // 优先使用命令行参数
  let startTime = parseDateArg('startDate');
  let endTime = parseDateArg('endDate');

  if (!startTime) startTime = config.startTime;
  if (!endTime) endTime = config.endTime;

  // 生成日期范围
  const dateRange = generateDateRange(startTime, endTime);

  let allTrades = [];
  let dailyResults = [];
  let allProfits = [];
  let cumulativeProfit = 0;

  console.log(`开始按天回测，总共 ${dateRange.length} 天`);

  // 按天获取数据并回测
  for (let i = 0; i < dateRange.length; i++) {
    const currentDate = dateRange[i];
    const dateStr = formatBeijingTime(currentDate);

    console.log(`正在处理第 ${i + 1}/${dateRange.length} 天: ${dateStr}`);

    // 获取当天数据
    const dayData = await getDataForDate(model, currentDate);

    if (dayData.length === 0) {
      console.log(`  ${dateStr}: 无数据`);
      continue;
    }

    console.log(`  ${dateStr}: 获取到 ${dayData.length} 条数据`);

    // 对当天数据进行回测
    const dayTrades = simulateSinglePositionStrategy(dayData, config);

    // 计算当天统计
    const dayProfit = dayTrades.reduce((sum, trade) => sum + trade.profit, 0);
    const dayWinCount = dayTrades.filter(trade => trade.result === "TP").length;

    cumulativeProfit += dayProfit;
    allProfits.push(dayProfit);
    allTrades = allTrades.concat(dayTrades);

    dailyResults.push({
      date: dateStr,
      trades: dayTrades.length,
      profit: dayProfit,
      cumulativeProfit,
      winCount: dayWinCount,
      winRate: dayTrades.length ? (dayWinCount / dayTrades.length * 100).toFixed(2) + "%" : "0%"
    });

    console.log(`  ${dateStr}: 交易 ${dayTrades.length} 次，收益 ${dayProfit.toFixed(4)}`);
  }

  // 计算总体统计
  let totalProfit = 0;
  let winCount = 0;
  for (const t of allTrades) {
    totalProfit += t.profit;
    if (t.result === "TP") winCount++;
  }

  console.log("\n=== 策略回测结果 ===");
  console.log("总交易次数:", allTrades.length);
  console.log("止盈次数:", winCount);
  console.log("胜率:", (allTrades.length ? (winCount / allTrades.length * 100).toFixed(2) : "0") + "%");
  console.log("总收益:", totalProfit.toFixed(4));
  console.log("平均每单收益:", allTrades.length ? (totalProfit / allTrades.length).toFixed(4) : "0");

  // 计算总体回撤
  const drawdownStats = calculateDrawdown(allProfits);

  console.log("\n=== 每日策略回撤分析 ===");
  console.log("最大回撤:", drawdownStats.maxDrawdown.toFixed(4));
  console.log("最终收益:", drawdownStats.finalValue.toFixed(4));
  console.log("峰值收益:", drawdownStats.peakValue.toFixed(4));
  console.log("回撤率:", drawdownStats.peakValue ? (drawdownStats.maxDrawdown / drawdownStats.peakValue * 100).toFixed(2) + "%" : "0%");

  console.log("\n=== 每日交易详情 ===");
  console.table(dailyResults.map(d => ({
    date: d.date,
    trades: d.trades,
    profit: d.profit.toFixed(4),
    cumulativeProfit: d.cumulativeProfit.toFixed(4),
    winCount: d.winCount,
    winRate: d.winRate
  })));

  console.log("\n=== 详细交易记录 ===");
  console.table(allTrades.map(t => ({
    symbol: t.symbol,
    gainPct: t.gainPct,
    entry_time: formatBeijingDateTime(new Date(t.entry_time)),
    exit_time: formatBeijingDateTime(new Date(t.exit_time)),
    entry: t.entry.toFixed(6),
    exit_price: t.exit_price.toFixed(6),
    closeToHighPct: t.closeToHighPct.toFixed(2),
    result: t.result,
    profit: t.profit.toFixed(6),
    positionSize: t.positionSize,
    consecutiveLosses: t.consecutiveLosses,
    times: t.times,
  })));

})()
